Release 10.1A: OpenEdge Development:
Progress 4GL Handbook


Adding an Order Line browse to the Customer window

You’ve completed the h-fetchOlines.p procedure. When it ends, it returns a temp-table with the OrderLines for the Order in it, along with the name and weight total from the Item table.

To use an include file to put the same code in multiple procedures:

  1. Open h-fetchOlines.p and copy the temp-table definition.
  2. Paste it into a new procedure window and save the procedure as h-ttOline.i:
  3. /* h-ttOline.i -- include file to define ttOline temp-table. */ 
    DEFINE TEMP-TABLE ttOline LIKE Orderline 
        FIELD ItemName LIKE ITEM.ItemName 
        FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt." . 
    

  4. Remove the code from h-fetchOlines.p (or just comment it out to remind you of what the include files replaces), and put in a reference to h-ttOline.i in its place:
  5. /* h-fetchOlines.p -- retrieve all orderlines for an Order 
       and return them in a temp-table. */ 
       {h-ttOline.i} 
       /* DEFINE TEMP-TABLE ttOline LIKE OrderLine 
           FIELD ItemName LIKE ITEM.ItemName 
           FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt." . */ 
            
       DEFINE INPUT  PARAMETER piOrderNum AS INTEGER    NO-UNDO. 
       DEFINE OUTPUT PARAMETER TABLE FOR ttOline. 
       FOR EACH OrderLine WHERE Orderline.OrderNum = piOrderNum,  
         ITEM OF OrderLine: 
           CREATE ttOline. 
           BUFFER-COPY OrderLine TO ttOline 
             ASSIGN ttOline.ItemName = ITEM.ItemName 
                    ttOline.TotalWeight = OrderLine.Qty * ITEM.Weight. 
       END. 
    

Remember that part of the purpose of this exercise is to give you a taste of what it is like to write separate Progress procedures for user interfaces and for data access and update code, so that you can ultimately distribute those procedures between client and server machines in a true enterprise application. In this simple example, both procedures run as part of the same session, but they could run more or less exactly the same in different OpenEdge sessions on completely different machines.

To add code to the CustOrderWin procedure to run h-fetchOlines.p and display the OrderLines in a browse of their own:

  1. Open h-CustOrderWin4.w in the AppBuilder.
  2. In the Definitions section, add a reference to h-ttOline.i:
  3. {h-ttOline.i} 
    /* DEFINE TEMP-TABLE ttOline LIKE Orderline 
        FIELD ItemName LIKE ITEM.ItemName 
        FIELD TotalWeight AS DECIMAL LABEL "Tot.Wgt." .  */ 
    

  4. Add a query definition for a query on this temp-table:
  5. DEFINE QUERY OlineQuery FOR ttOline. 
    

    When you first built this window, you let the AppBuilder generate the browse definition for the Order browse for you. This time you’ll write it yourself. First of all, this is to let you say you wrote one browse definition in your life, even if you never write another one. And you might never have to, given that the AppBuilder can generate it for you.

    But there is another reason for you to write the browse definition: the AppBuilder is not great at generating queries and browses based on temp-tables, simply because there is no database schema where you can look up the definitions. You can define them using a special design-time database called temp-db, but because you’re here to learn the language, it’s better just to write the definition yourself.

  6. Put this browse definition for the temp-table after the other elements in the Definitions section. Select these fields from the ttOline table, including the Item Name and Weight from the Item table:
  7. DEFINE BROWSE OlineBrowse 
      QUERY OlineQuery NO-LOCK DISPLAY 
          ttOline.Ordernum  
          ttOline.LineNum LABEL "Line" 
          ttOline.ItemNum LABEL "Item" FORMAT "ZZZ9" 
          ttOline.ItemName FORMAT "x(20)" 
          ttOline.TotalWeight 
          ttOline.Price FORMAT "ZZ,ZZ9.99" 
          ttOline.Qty 
          ttOline.Discount 
          ttOline.ExtendedPrice LABEL "Ext.Price" FORMAT "ZZZ,ZZ9.99" 
        WITH NO-ROW-MARKERS SEPARATORS 7 DOWN ROW-HEIGHT-CHARS .57. 
    

    Remember that your BUFFER-COPY from the OrderLine table gives you all the fields from that table in your temp-table, but you don’t have to use all of them in the browse.

    When the AppBuilder generates a browse, it always gives it a specific size based on how you lay it out (generating the phrase SIZE x BY y). In this case, you define a number of rows to display instead with the 7 DOWN phrase and leave out the size altogether. That way, Progress displays it tall enough to show seven rows of data and wide enough to display all the fields you’ve selected.

    Now you need to run the procedure that fetches the Order Lines each time a row is selected in the Order browse. The event that is fired when a row is selected is called VALUE-CHANGED.

  8. In the Section Editor, define this trigger on VALUE-CHANGED of the OrderBrowse:
  9. DO: 
      RUN h-fetchOlines.p (INPUT Order.OrderNum, OUTPUT TABLE ttOline). 
      OPEN QUERY OlineQuery FOR EACH ttOline. 
      DISPLAY OlineBrowse WITH FRAME CustQuery. 
      ENABLE OlineBrowse WITH FRAME CustQuery. 
    END. 
    

    The trigger code runs the procedure, passing in the current Order number from the Order buffer and getting a temp-table back. Then it opens the OlineQuery. Because the DEFINE BROWSE statement associates the query with the new browse, the rows from the temp-table are automatically displayed in the browse. The DISPLAY statement displays the browse itself in the same frame with everything else. Without more specific instructions on where to place it, Progress places it to the right of the last object that’s already defined for the frame, which is the Order browse. You could also use ROW and COLUMN attributes on the DISPLAY statement to display the new browse somewhere else. Finally, enabling the browse lets the user select rows in it and scroll in it if it has too many rows to display at once. This code does not enable the individual cells in the browse for update.

    The VALUE-CHANGED trigger fires whenever the user selects a different row in the browse. But there are two other times when a row is selected. The first is when the window first comes up. The Order browse then holds the Orders for the first Customer, and the first of those Orders is selected implicitly.

  10. Make sure the VALUE-CHANGED trigger fires at that time, in the Main Block of the window procedure, by adding a line to APPLY the VALUE-CHANGED trigger on startup:
  11. MAIN-BLOCK: 
    DO ON ERROR   UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK 
       ON END-KEY UNDO MAIN-BLOCK, LEAVE MAIN-BLOCK: 
      RUN enable_UI. 
      ASSIGN cState = Customer.State 
             iMatches = NUM-RESULTS("CustQuery"). 
       DISPLAY cState iMatches WITH FRAME CustQuery. 
      APPLY "VALUE-CHANGED" TO OrderBrowse. 
    END. 
    

    The second place where an Order is implicitly selected is whenever the user presses one of the buttons that selects a new Customer. This reopens the Order query, and you want the OrderLines for the first Order for that Customer to be retrieved.

    Because there are four buttons with almost exactly the same code on them, this is another good place to use an include file. As mentioned earlier, the one keyword that is different in these triggers is whether it is a GET FIRST, NEXT, PREV, or LAST. So you make that keyword an argument to the include file.

  12. Create an include file for the four buttons:
    1. Copy the code from the BtnFirst CHOOSE trigger and paste it into a new procedure window.
    2. Replace the FIRST keyword with the include file argument marker {1}.
    3. Add the same statement as you did in the Main Block to APPLY the VALUE-CHANGED event.
    4. Save this code as h-ButtonTrig1.i:
    5. /* h-ButtonTrig1.i -- include file for the First/Next/Prev/Last 
      buttons in h-CustOrderWin4.w. */ 
         GET {1} CustQuery. 
        IF AVAILABLE Customer THEN  
         DISPLAY Customer.CustNum Customer.Name Customer.Address 
                 Customer.City Customer.State  
            WITH FRAME CustQuery IN WINDOW CustWin. 
        {&OPEN-BROWSERS-IN-QUERY-CustQuery} 
        APPLY "VALUE-CHANGED" TO OrderBrowse. 
      

  13. In each of the four CHOOSE triggers, replace the trigger code with a reference to the h-ButtonTrig.i include file, passing in the appropriate GET keyword, as in this BtnFirst trigger:
  14. { h-ButtonTrig1.i FIRST } 
    

    Now your procedure is read to retrieve and display OrderLines.

  15. Widen the window and its frame substantially by dragging the right edge out further to the right, to make room for the OrderLine browse.
  16. Run the window to see the effect of your changes:

Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095